home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
t3_1
/
doc.lha
/
documentation
/
manual
/
foreign.mss
< prev
next >
Wrap
Text File
|
1987-06-30
|
6KB
|
143 lines
@Part(ForeignCode, Root "TMAN.MSS")
@Chap(Foreign Code)
@section[Foreign Objects]
@i[Xenoids] are used to hold single machine pointers
which @tau[] needs to use, but which are not
@tau[] objects. Two examples are: the file
descriptor that the operating system returns when a file is opened; and,
the address of a system or non-@tau[] routine.
@i[Bit vectors] can be used to hold foreign objects larger than a
single machine pointer. [Bit vectors are not yet implemented].
@section[Calling Foreign Code in VAX @tau[]]
The form of interest here is @tc[CALL-XENOID].
@section[Calling Foreign Code in Apollo @tau[]]
@desc[(EXTERNAL-SYMBOL-ADDRESS @i[string])]
This routine returns a non-@tau[] pointer that is the machine address
of the process global routine whose name is @i[string]. To get a xenoid,
@tc[X], that can be passed to @tc[CALL-XENOID] to do program invocation,
one might say:
@begin[ProgramExample]
(SET X (MAKE-XENOID (EXTERNAL-SYMBOL-ADDRESS "pgm_$invoke")))
@end[ProgramExample]
@EndDesc[EXTERNAL-SYMBOL-ADDRESS]
@desc[(CALL-XENOID @i[ret-info-1 ret-info-2 callable-xenoid . argument-items])]
Call the foreign code pointed to by the @i[callable-xenoid] using
the Apollo calling sequence. The @i[callable-xenoid] is create as described
above.
Since the Apollo calling sequence is call by reference, and @tau[]'s is call
by value, extra space is need on the stack for pointers (the @qu"references"),
to the values that were intended as arguments to the Apollo code being called.
The lowest level call to invoke Apollo code (i.e. code
that uses the Apollo calling sequence) is designed so that the stack
pointer need not be adjusted before making the foreign call.
This is done by requiring extra arguments to @tc[CALL-XENOID].
In addition to providing room on the stack, the extra arguments also
indicate conversions that should be performed on the @tau[] values
that are on the stack, to make them suitable for the foreign code to
use. To complicate things further, the Apollo and @tau[] calling
sequences require arguments in the opposite order.
Argument items can be: a single character that
holds a place for a @qu"reference" and may indicate a data conversion,
a @tau[] value. In preparing for the call to foreign code
some values are not touched, some are converted to a format
suitable for the foreign code, and some are converted according to one of the
argument specs.
There are two kinds of argument items -- value items, and reference
items. The value items occur before the reference items. For every
value item there is a corresponding reference item, but there may be
reference items with no value items. For each parameter to the foreign
code there is one reference item. The last reference item in the
@tc[CALL-XENOID] form refers to the first foreign code parameter; the
first reference item to the last foreign code parameter. If a reference
item @qu"needs" a value item, it uses (gets? matches?) the next unused
one, starting from the first (leftmost) value item in the form.
If you want to pass a string just put the @tau[] string in the appropriate
position in the reference items. If you want to pass the length of
that string, put a lower case character @qu"s," @tc[#\s],
in the appropriate position in the reference items. Notice
that @tc[#\s] gives a reference to a word long integer that is the
actual length field of the last string encountered in the
reference items, starting from the rightmost one.
To pass a 32 bit integer, put @tc[#\l] in the reference items and
put the integer in corresponding position in the value items; use
@tc[#\w] for a 16 bit integer.
Arbitrary extends can be passed by putting them in the reference
items at the appropriate place. Bit vectors are arbitrary
extends, as are xenoids.
For example, suppose we want to call a PASCAL procedure, @tc[x_$test],
that expects
a string (packed array of char), it length as a word long integer,
a 16 bit integer, a 32 bit integer, and a status code.
Assume @tc[I] is the @tau[] fixnum that we want to pass of the word
parameter, @tc[J] will be passed as the longword.
We might write:
@begin[ProgramExample]
(SET X_$TEST (MAKE-XENOID (EXTERNAL-SYMBOL-ADDRESS "x_$test")))
(SET STATUS (MAKE-XENOID 0))
(CALL-XENOID 'VOID NIL X_$TEST I J STATUS #\l #\w #\s "My string")
@end[ProgramExample]
@tc[XENOID-POINTER] is a procedure that returns the 32 bit field of a
given xenoid. Be careful, it returns an unsafe value.
The manner in which the value is returned from the foreign code is controlled
by the two arguments @i[ret-info-1] and @i[ret-info-2]. The Apollo
calling sequence allows three variations on the value returned:
@begin[display]
return no value
return an @qu(address)
return up to 32 bits of data
@end[display]
If the foreign code does indeed return a value, @tau[] can:
@begin[display]
convert value to a fixnum (multiply by 8)
convert value to a pointer (a no-op actually)
store value in a xenoid as a fixnum
store value in a xenoid as a pointer
@end[display]
Of the 12 possibilities, 7 are legal and are encoded in the two info
arguments. Roughly speaking, @i[ret-info-1] describes the form
of the return value from the Apollo side, and @i[ret-info-2] describes
the value from the @tau[] side.
@begin[display]
@tabdivide(6)
@i[ret-info-1]@\@i[ret-info-2]@\action
@tc['ADDR] @\@tc['POINTER] @\Return returned address as a @tau[] pointer.
@tc['ADDR] @\@tc['FIXNUM] @\Return returned address as a @tau[] fixnum.
@tc['ADDR] @\@i[xenoid] @\Store returned address into the given @i[xenoid].
@\ @\(Return @i[xenoid])
@tc['DATA] @\@tc['POINTER] @\Return 32 bits of returned data as a @tau[] pointer.
@tc['DATA] @\@tc['FIXNUM] @\Return 29 bits of returned data as a @tau[] fixnum.
@tc['DATA] @\@i[xenoid] @\Store 32 bits of data into the given @i[xenoid].
@\ @\(Return @i[xenoid])
@tc['VOID]@\@i[anything] @\Ignore foreign code's return value (if any).
@\ @\(Return @i[anything])
@end[display]
Yet to be discussed:
@begin[itemize]
OUT parameters that are integers (long or word) are a pain in the
neck - you must use a xenoid to box the data yourself
it is safest (essential?) to gc-defer while doing call-xenoid
The higher level interface -- coping with PASCAL records
@end[itemize]
@EndDesc[CALL-XENOID]